package cz.muni.fi.pa036is.controllers;

import cz.muni.fi.pa036is.dto.CommentFormTO;
import cz.muni.fi.pa036is.dto.LoginDTO;
import cz.muni.fi.pa036is.dto.MatchDetailTO;
import cz.muni.fi.pa036is.dto.MatchFormTO;
import cz.muni.fi.pa036is.dto.RoundGridTO;
import cz.muni.fi.pa036is.dto.SeasonBasicTO;
import cz.muni.fi.pa036is.dto.SeasonDetailTO;
import cz.muni.fi.pa036is.dto.SeasonFormTO;
import cz.muni.fi.pa036is.dtoconverters.SeasonConverter;
import cz.muni.fi.pa036is.entity.Round;
import cz.muni.fi.pa036is.servicesinterface.CommentService;
import cz.muni.fi.pa036is.servicesinterface.ComplaintService;
import cz.muni.fi.pa036is.servicesinterface.MatchService;
import cz.muni.fi.pa036is.servicesinterface.PersonService;
import cz.muni.fi.pa036is.servicesinterface.RoundService;
import cz.muni.fi.pa036is.servicesinterface.SeasonService;
import cz.muni.fi.pa036is.utilities.DateEditor;
import cz.muni.fi.pa036is.utilities.DateTimeEditor;
import cz.muni.fi.pa036is.validators.CommentValidator;
import cz.muni.fi.pa036is.validators.MatchValidator;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import javax.servlet.http.HttpSession;
import org.postgresql.util.PSQLException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;

@Controller
@SessionAttributes("match")
public class MatchController {

    @Autowired
    private MatchService matchService;
    @Autowired
    private PersonService personService;
    @Autowired
    private SeasonService seasonService;
    @Autowired
    private RoundService roundService;
    @Autowired
    private ComplaintService complaintService;
    @Autowired
    private CommentService commentService;

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(Timestamp.class, new DateTimeEditor());
    }

    // Detail
    @RequestMapping(value = "/admin/match/detail", params = "id")
    public String detail(@RequestParam("id") Long id, ModelMap model) {
        MatchDetailTO match = this.matchService.getMatchDetail(id);
        List<RoundGridTO> rounds = this.roundService.getAllRoundsForMatch(id);

        model.addAttribute("match", match);
        model.addAttribute("rounds", rounds);
        model.addAttribute("player1", this.personService.getPersonDetail(match.getPlayer1Id()));
        model.addAttribute("player2", this.personService.getPersonDetail(match.getPlayer2Id()));
        model.addAttribute("complaints", this.complaintService.getComplaintsByMatch(id));
        model.addAttribute("comment", new CommentFormTO());
        model.addAttribute("comments", this.commentService.getAllCommentsForMatch(id));
        model.addAttribute("login", new LoginDTO());

        return "/admin/match/detail";
    }

    @RequestMapping(value = "/admin/match/addComment", method = RequestMethod.POST)
    public String addComment(@Validated @ModelAttribute("comment") CommentFormTO comment,
            @Validated @ModelAttribute("match") MatchDetailTO match,
            BindingResult result, ModelMap model,
            HttpSession session) {

        if (result.hasErrors()) {
            
            
            return "redirect:/admin/match/detail?id=" + comment.getMatchId();
        }

        comment.setMatchId(match.getId());
        this.commentService.addComment(comment);

        return "redirect:/admin/match/detail?id=" + comment.getMatchId();
    }

    @RequestMapping(value = "/admin/match/edit", params = {"id", "seasonId"})
    public String edit(@RequestParam("id") Long id, @RequestParam("seasonId") Long seasonId, ModelMap model) {

        SeasonDetailTO s = this.seasonService.getSeasonDetail(seasonId);

        MatchFormTO match = null;
        if (id == null || id < 0) {
            match = new MatchFormTO();

            SeasonBasicTO season = SeasonConverter.convertToSeasonBasicTO(s);
            match.setSeason(season);
            match.setSeasonId(season.getId());
        } else {
            match = this.matchService.getMatchForm(id);

            if (match.getSeason() == null) {
                SeasonBasicTO season = SeasonConverter.convertToSeasonBasicTO(s);
                match.setSeason(season);
            }
        }

        model.addAttribute("match", match);
        model.addAttribute("players", this.personService.getAllPersonsForDropDown());

        return "/admin/match/edit";
    }

    @RequestMapping(value = "/admin/match/edit", method = RequestMethod.POST)
    public String edit(@Validated @ModelAttribute("match") MatchFormTO match, BindingResult result, ModelMap model,
            HttpSession session) {

        
        MatchValidator matchValidator = new MatchValidator();
        matchValidator.validate(match, result);

        if (result.hasErrors()) {

            
            
            HashMap<String, String> errors = new HashMap<String, String>();
            for (FieldError error : result.getFieldErrors()) {
                errors.put(error.getField(), error.getDefaultMessage());
            }
            model.put("errors", errors);
            for (ObjectError o : result.getAllErrors()) {
                System.err.println(o);

            }
            
            model.put("match", match);
            model.addAttribute("players", this.personService.getAllPersonsForDropDown());
            
            return "/admin/match/edit";
        }

        if (match.getId() == null || match.getId() < 0) {
            this.matchService.addMatch(match);
        } else {
            this.matchService.editMatch(match);
        }


        return "redirect:/admin/match/detail?id=" + match.getId();
    }

    @RequestMapping(value = "/admin/match/remove", params = {"id", "seasonId"})
    public String remove(@RequestParam("id") Long id, @RequestParam("seasonId") Long seasonId, ModelMap model, HttpSession session) {

        try {
            matchService.deleteMatch(id);
        } catch (Exception ex) {
            model.addAttribute("messages", "Cannot remove match record, because there exists round, comments or complaints");
            return "redirect:/admin/season/detail?id=" + seasonId;
        }

        return "redirect:/admin/season/detail?id=" + seasonId;
    }
}
